home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Joy 1: Lollypop
/
Joy #1: Lollypop.iso
/
viewer
/
unixview
/
xgiftar.z
/
xgiftar
/
compress.c
< prev
next >
Wrap
C/C++ Source or Header
|
1991-05-20
|
4KB
|
167 lines
/* compress.c:
*
* compress a colormap by removing unused or duplicate RGB colors. this
* uses a 15-bit true color pixel as an index into a hash table of pixel
* values (similar to the technique used in reduce.c).
*
* jim frost 10.05.89
*
* Copyright 1991 Jim Frost.
* See included file "copyright.h" for complete copyright information.
*/
#include "copyright.h"
#include "image.h"
/* this converts a TLA-style pixel into a 15-bit true color pixel
*/
#define TLA_TO_15BIT(TABLE,PIXEL) \
((((TABLE).red[PIXEL] & 0xf800) >> 1) | \
(((TABLE).green[PIXEL] & 0xf800) >> 6) | \
(((TABLE).blue[PIXEL] & 0xf800) >> 11))
/* these macros extract color intensities from a 15-bit true color pixel
*/
#define RED_INTENSITY(P) (((P) & 0x7c00) >> 10)
#define GREEN_INTENSITY(P) (((P) & 0x03e0) >> 5)
#define BLUE_INTENSITY(P) ((P) & 0x001f)
#define NIL_PIXEL 0xffffffff
void compress(image, verbose)
Image *image;
unsigned int verbose;
{ Pixel hash_table[32768];
Pixel *pixel_table;
Pixel *pixel_map;
Pixel index, oldpixval, newpixval;
byte *pixptr;
unsigned int x, y, badcount, dupcount;
RGBMap rgb;
goodImage(image, "compress");
if (!RGBP(image) || image->rgb.compressed) /* we're AT&T */
return;
if (verbose) {
printf(" Compressing colormap...");
fflush(stdout);
}
/* initialize hash table and allocate new RGB intensity tables
*/
for (x= 0; x < 32768; x++)
hash_table[x]= NIL_PIXEL;
newRGBMapData(&rgb, image->rgb.used);
rgb.size= image->rgb.used;
rgb.used= 0;
pixel_table= (Pixel *)lmalloc(sizeof(Pixel) * image->rgb.used);
pixel_map= (Pixel *)lmalloc(sizeof(Pixel) * image->rgb.used);
for (x= 0; x < image->rgb.used; x++)
pixel_map[x]= NIL_PIXEL;
pixptr= image->data;
dupcount= badcount= 0;
for (y= 0; y < image->height; y++)
for (x= 0; x < image->width; x++) {
oldpixval= memToVal(pixptr, image->pixlen);
if (oldpixval > image->rgb.used) {
badcount++;
oldpixval= 0;
}
/* if we don't already know what value the new pixel will have,
* look for a similar pixel in hash table.
*/
if (pixel_map[oldpixval] == NIL_PIXEL) {
index= TLA_TO_15BIT(image->rgb, oldpixval);
/* nothing similar
*/
if (hash_table[index] == NIL_PIXEL) {
newpixval= rgb.used++;
hash_table[index]= newpixval;
}
/* we've seen one like this before; try to find out if it's an
* exact match
*/
else {
newpixval= hash_table[index];
for (;;) {
/* if the color is the same as another color we've seen,
* use the pixel that the other color is using
*/
if ((rgb.red[newpixval] == image->rgb.red[oldpixval]) &&
(rgb.green[newpixval] == image->rgb.green[oldpixval]) &&
(rgb.blue[newpixval] == image->rgb.blue[oldpixval])) {
pixel_map[oldpixval]= newpixval; /* same color */
dupcount++;
goto move_pixel;
}
/* if we're at the end of the chain, we're the first pixel
* of this color
*/
if (pixel_table[newpixval] == NIL_PIXEL) /* end of the chain */
break;
newpixval= pixel_table[newpixval];
}
pixel_table[newpixval]= rgb.used;
newpixval= rgb.used++;
}
pixel_map[oldpixval]= newpixval;
pixel_table[newpixval]= NIL_PIXEL;
rgb.red[newpixval]= image->rgb.red[oldpixval];
rgb.green[newpixval]= image->rgb.green[oldpixval];
rgb.blue[newpixval]= image->rgb.blue[oldpixval];
}
/* change the pixel
*/
move_pixel:
valToMem(pixel_map[oldpixval], pixptr, image->pixlen);
pixptr += image->pixlen;
}
lfree(pixel_table);
lfree(pixel_map);
if (badcount)
if (verbose)
printf("%d out-of-range pixels, ", badcount);
else
fprintf(stderr, "Warning: %d out-of-range pixels were seen\n",
badcount);
if (verbose) {
if ((rgb.used == image->rgb.used) && !badcount)
printf("no improvment\n");
else {
int unused= image->rgb.used - rgb.used - dupcount;
if (dupcount)
printf("%d duplicate%s and %d unused color%s removed...",
dupcount, (dupcount == 1 ? "" : "s"),
unused, (unused == 1 ? "" : "s"));
printf("%d unique color%s\n",
rgb.used, (rgb.used == 1 ? "" : "s"));
}
}
/* image is converted; now fix up its colormap
*/
freeRGBMapData(&(image->rgb));
image->rgb= rgb;
image->rgb.compressed= 1;
}